package com.pi.shisan.component;

import com.pi.shisan.AsCloseable;
import com.pi.shisan.component.util.AnimationThread;
import com.pi.shisan.util.spipoint.DataWriter;
import com.pi.shisan.util.spipoint.MultipleXyToSpiConverter;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class AnimationComponent extends BaseAbstractComponent implements AsCloseable {

    protected AnimationThread animationThread;

    private final static int WAITING = 0;
    private final static int STARTING = 1;
    private final static int RUNNING = 2;
    private final static int DESTROYED = 3;


    /**
     * 0 - 未启动
     * 1 - 正在启动
     * 2 - 启动完毕
     * 3 - 已销毁
     */
    private AtomicInteger threadStatus = new AtomicInteger(0);

    public AnimationComponent(MultipleXyToSpiConverter spi, DataWriter dataWriter) {
        super(spi, dataWriter);
    }

    @Override
    public final void start() {
        if (threadStatus.compareAndSet(WAITING,STARTING)) {
            try {
                animationThread = prepareAnimation();
                animationThread.start();
                threadStatus.compareAndSet(STARTING,RUNNING);
            } catch (Exception e) {
                threadStatus.compareAndSet(STARTING,DESTROYED);
                throw e;
            }
        }
    }

    @Override
    public final void destroy() {
        while (!Objects.equals(threadStatus.get(), DESTROYED)) {
            if (threadStatus.compareAndSet(WAITING,DESTROYED)) {
                //DO NOTING, NOTING INIT.
                break;
            }
            if (threadStatus.compareAndSet(RUNNING,DESTROYED)) {
                animationThread.setDestroy();
                animationThread.awaitDestroy();
                break;
            }
        }
        prepareDestroy();
    }

    @Override
    public void close() {
        destroy();
    }

    protected abstract AnimationThread prepareAnimation();

    protected void prepareDestroy() {}

    protected boolean waitStart() {
        while (!Objects.equals(threadStatus.get(), RUNNING)) {
            if (threadStatus.get() == RUNNING) {
                break;
            }
            Thread.yield();
        }
        return Objects.equals(threadStatus.get(), RUNNING);
    }
}
